package service

import (
	"bufio"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mini-gde/client"
	"mini-gde/model"
	"net/http"
	"net/http/cookiejar"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/docker/docker/pkg/archive"
	"k8s.io/client-go/util/homedir"

	"github.com/docker/docker/api/types"
)

type Image struct {
	Id         string `json:"Id"`
	Created    string
	Repository string
	Tags       string
	Size       int64
}

var authConfig = types.AuthConfig{
	Username: "chintensakai",
	Password: "gaosan16ban",
}

func GetImages() []Image {
	// ctx := context.Background()

	// cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation(),
	// 	client.WithHost("tcp://192.168.120.181:2375"))

	// 本地
	// cli, err := client.NewClientWithOpts(client.FromEnv)
	// if err != nil {
	// 	panic(err)
	// }

	images, err := client.Client.ImageList(client.Ctx, types.ImageListOptions{})

	result := make([]Image, 0, len(images))
	if err != nil {
		panic(err)
	}

	for _, image := range images {
		if len(image.RepoTags) == 0 {
			continue
		}
		created := time.Unix(image.Created, 0).Format("2006-01-02 15:04:05")
		tmp := Image{
			Id:         image.ID[8:24],
			Created:    created,
			Repository: strings.Split(image.RepoTags[0], ":")[0],
			Tags:       strings.Split(image.RepoTags[0], ":")[1],
			Size:       image.Size,
		}
		result = append(result, tmp)
	}
	return result
}

// build image
func BuildImageByDockerfile(images string) error {
	path := homedir.HomeDir() + "/tmp/apps"
	tar, err := archive.TarWithOptions(path+"/"+images+"/", &archive.TarOptions{})
	fmt.Println(path + "/" + images + "/")
	if err != nil {
		fmt.Println(err)
		return err
	}
	tag := "10.0.37.153:5000/" + images + ":0.0.1"
	opts := types.ImageBuildOptions{
		Dockerfile: "Dockerfile",
		Tags:       []string{tag},
		Remove:     true,
	}
	res, err := client.Client.ImageBuild(client.Ctx, tar, opts)
	fmt.Println(res.Body)
	if err != nil {
		fmt.Println(err)
		return err
	}

	defer res.Body.Close()
	scanner := bufio.NewScanner(res.Body)
	for scanner.Scan() {
		lastLine := scanner.Text()
		fmt.Println(lastLine)
	}
	err = imagePush(tag)
	if err != nil {
		fmt.Println(err)
		return err
	}
	//destorytemp(path)
	return nil
}

func destorytemp(path string) {

	filepath.Walk(path, func(path string, fi os.FileInfo, err error) error {
		if nil == fi {
			return err
		}
		if !fi.IsDir() {
			return nil
		}
		name := fi.Name()

		if strings.Contains(name, "temp") {

			fmt.Println("temp file name:", path)

			err := os.RemoveAll(path)
			if err != nil {
				fmt.Println("delet dir error:", err)
			}
		}
		return nil
	})

}

// push image
func imagePush(tag string) error {
	authConfigBytes, _ := json.Marshal(authConfig)
	authConfigEncoded := base64.URLEncoding.EncodeToString(authConfigBytes)

	opts := types.ImagePushOptions{RegistryAuth: authConfigEncoded}
	rd, err := client.Client.ImagePush(client.Ctx, tag, opts)
	if err != nil {
		return err
	}

	defer rd.Close()
	// 打印镜像推送的输出
	_, err = io.Copy(os.Stdout, rd)
	if err != nil {
		fmt.Println("Err: read image push response error,", err.Error())
		return err
	}
	return nil
}

// SaveImage save image to tar file
func SaveImage(ids []string, path string) error {
	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		fmt.Println("Err: save image response error,", err.Error())
		return err
	}
	defer file.Close()

	out, err := client.Client.ImageSave(client.Ctx, ids)
	if err != nil {
		fmt.Println("Err: save image response error,", err.Error())

		return err
	}

	if _, err = io.Copy(file, out); err != nil {
		fmt.Println("Err: save image response error,", err.Error())

		return err
	}

	return nil
}
func GetHarborList() []model.HarborImage {
	// 获取所有project https://www.harbor.mobi//api/v2.0/projects?page_size=100000
	// 根据project获取所有repository  https://www.harbor.mobi//api/v2.0/projects/test/repositories?page_size=100000
	// 根据repository获取所有的artifact https://www.harbor.mobi//api/v2.0/projects/test/repositories/zhangxueliang%252Fmyapp/artifacts?pageSize=100000
	// 【参数不详】根据artifact获取所有的tag https://www.harbor.mobi//api/v2.0/projects/test/repositories/zhangxueliang%252Fmyapp/artifacts/xxx/tags?pageSize=100000
	harbors := []model.HarborImage{}

	// 获取所有project https://www.harbor.mobi//api/v2.0/projects?page_size=100000
	project_url := "https://www.harbor.mobi/api/v2.0/projects?page_size=100"
	project_slice := []string{}
	repository_slice := []string{}
	tag_slice := []string{}
	var project_map_arr []map[string]string
	var repository_map_arr []map[string]string
	var artifact_map_arr []map[string]interface{}
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	//http cookie接口
	cookieJar, _ := cookiejar.New(nil)
	c := &http.Client{
		Jar:       cookieJar,
		Transport: tr,
	}
	//c.Get("https://192.169.0.199:8080/Versty/app: ")
	project_resp, project_err := c.Get(project_url)
	if project_err != nil {
		fmt.Println(project_err)
		//return err
	}
	fmt.Println("resp ", project_resp)
	defer project_resp.Body.Close()
	project_resp_body, _ := ioutil.ReadAll(project_resp.Body)
	// project_resp_body_jsonstr := string(project_resp_body)
	// fmt.Printf(">>>>>>>>>>>>>>>>>>>>>>>>> %v \n", project_resp_body_jsonstr)
	json.Unmarshal(project_resp_body, &project_map_arr)
	for _, p := range project_map_arr {
		project_name := p["name"]
		project_slice = append(project_slice, project_name)
		// 根据project获取所有repository  https://www.harbor.mobi//api/v2.0/projects/test/repositories?page_size=100000
		repository_url := fmt.Sprintf("https://www.harbor.mobi/api/v2.0/projects/%v/repositories?page_size=100", project_name)
		repository_resp, repository_err := c.Get(repository_url)
		if repository_err != nil {
			fmt.Println("repositroy", repository_err)
			//return repository_err
		}
		defer repository_resp.Body.Close()
		repository_resp_body, _ := ioutil.ReadAll(repository_resp.Body)
		json.Unmarshal(repository_resp_body, &repository_map_arr)
		for _, r := range repository_map_arr {
			rname := r["name"]
			firstIdx := strings.Index(rname, "/")
			repository_name := rname[firstIdx+1:]
			repository_slice = append(repository_slice, repository_name)
			// 根据repository获取所有的artifact https://www.harbor.mobi/api/v2.0/projects/test/repositories/zhangxueliang%252Fmyapp/artifacts?pageSize=100000
			// "test/zhangxueliang/myapp"
			r_name := strings.Replace(repository_name, "/", "%252F", -1)
			artifact_url := fmt.Sprintf("https://www.harbor.mobi/api/v2.0/projects/%v/repositories/%v/artifacts?pageSize=100", project_name, r_name)
			artifact_resp, artifact_err := c.Get(artifact_url)
			if artifact_err != nil {
				fmt.Println("article ", artifact_err)
				return nil
			}
			defer artifact_resp.Body.Close()
			artifact_resp_body, _ := ioutil.ReadAll(artifact_resp.Body)
			json.Unmarshal(artifact_resp_body, &artifact_map_arr)
			for _, a := range artifact_map_arr {
				if a != nil && a["tags"] != nil {
					tags := a["tags"].([]interface{})
					tag_map := tags[0].(map[string]interface{})
					fmt.Println(tag_map)
					tag_name := tag_map["name"].(string)
					tag_slice = append(tag_slice, tag_name)
					pull_time := tag_map["pull_time"].(string)
					t8, _ := time.Parse(time.RFC3339, pull_time)
					push_time := tag_map["push_time"].(string)
					t9, _ := time.ParseInLocation(time.RFC3339, push_time, time.Local)
					t9 = t9.Add(8 * time.Hour)
					image := model.HarborImage{
						HarborUrl:      "https://www.harbor.mobi/",
						HarborUser:     "admin",
						HarborPwd:      "123456pwd",
						ImageName:      repository_name,
						ImageTagName:   tag_name,
						HarborProjName: project_name,
						AppName:        project_name,
						PullTime:       t8.String(),
						PushTime:       t9.Format("2006-01-02 15:04:05"),
					}
					fmt.Println(image)
					harbors = append(harbors, image)
				}
			}
		}

	}
	return harbors

}

// 根据 GMT 字符串获取对应的时间
func GetGmtTime(secStr string) (*time.Time, error) {
	// 25 Feb 2021 02:23:17 GMT
	formatTimeStr := "02 Jan 2006 15:04:05 GMT"
	start, err := time.Parse(formatTimeStr, secStr)
	if err == nil {
		realTime := start.Add(8 * time.Hour)
		return &realTime, nil
	} else {
		return nil, err
	}
}
